using System;
using System.Collections;
using System.Text;
using System.IO;
using Refly.CodeDom;
using System.Text.RegularExpressions;
using System.Reflection;

namespace Doubler
{
    class DoubleMaker
    {
        
#region Fields

        private string _AsmPath;
        private string _TypeName;
        private int _LineNumber;
        private string _SourceFilePath;
        private string _SolutionFilePath;
        private string _DoubleFilePath;
        private string _ProjectFilePath;
        private string _DirectoryPath;
        private string _Language;
        private FileInfo _OutFile;
        private Type _DoubleSubject;

#endregion
        
#region Properties

        public string AsmPath
        {
            get
            {
                return _AsmPath;
            }
            set
            {
                if (_AsmPath == value)
                    return;
                _AsmPath = value;
            }
        }
        public string TypeName
        {
            get
            {
                return _TypeName;
            }
            set
            {
                if (_TypeName == value)
                    return;
                _TypeName = value;
            }
        }
        public int LineNumber
        {
            get
            {
                return _LineNumber;
            }
            set
            {
                if (_LineNumber == value)
                    return;
                _LineNumber = value;
            }
        }
        public string SourceFilePath
        {
            get
            {
                return _SourceFilePath;
            }
            set
            {
                if (_SourceFilePath == value)
                    return;
                _SourceFilePath = value;
            }
        }
        public string SolutionFilePath
        {
            get
            {
                return _SolutionFilePath;
            }
            set
            {
                if (_SolutionFilePath == value)
                    return;
                _SolutionFilePath = value;
            }
        }
        public string DoubleFilePath
        {
            get
            {
                return _DoubleFilePath;
            }
            set
            {
                if (_DoubleFilePath == value)
                    return;
                _DoubleFilePath = value;
            }
        }
        public string ProjectFilePath
        {
            get
            {
                return _ProjectFilePath;
            }
            set
            {
                if (_ProjectFilePath == value)
                    return;
                _ProjectFilePath = value;
            }
        }
        public string DirectoryPath
        {
            get
            {
                return _DirectoryPath;
            }
            set
            {
                if (_DirectoryPath == value)
                    return;
                _DirectoryPath = value;
            }
        }
        public string Language
        {
            get
            {
                return _Language;
            }
            set
            {
                if (_Language == value)
                    return;
                _Language = value;
            }
        }

        public FileInfo OutFile
        {
            get
            {
                if (_OutFile == null)
                    this.CreateHandleOutFile();
                return _OutFile;
            }
            set
            {
                _OutFile = value;
            }
        }

        public Type DoubleSubject
        {
            get
            {
                if (_DoubleSubject == null)
                    this.FindTypeToDouble();
                return _DoubleSubject;
            }
            set
            {
                _DoubleSubject = value;
            }
        }

#endregion
        
#region Constructor

        public DoubleMaker(string asmPath, string typeName, int lineNumber, string sourceFilePath, string solutionFilePath, string doubleFilePath, string projectFilePath, string directoryPath, string language)
        {
            _AsmPath = asmPath;
            _TypeName = typeName;
            _LineNumber = lineNumber;
            _SourceFilePath = sourceFilePath;
            _SolutionFilePath = solutionFilePath;
            _DoubleFilePath = doubleFilePath;
            _ProjectFilePath = projectFilePath;
            _DirectoryPath = directoryPath;
            _Language = language;
        }

        public DoubleMaker()
        {
            
        }

#endregion

        public void Test()
        {
            this.LineNumber = 34;
            this.SourceFilePath = @"C:\Projects\EF_COTS\1.6.1\Product\Production\EF.Common.Infrastructure\Security\ISharedSecurity.vb";
            this.AsmPath = @"C:\Projects\EF_COTS\1.6.1\Product\Production\EF.Common.Infrastructure\bin\EF.Common.Infrastructure.dll";
            this.DirectoryPath = @"C:\temp\double";
            this.Language = "vb";
            this.CreateDouble();
        }

        public void CreateDouble()
        {
            CodeLanguage Lang = CodeLanguage.Cs;
            if (this.Language == "vb")
            {
                Lang = CodeLanguage.Vb;
            }
            else if (this.Language == "cs")
            {
                Lang = CodeLanguage.Cs;
            }
            RecorderTemplate Generator = new RecorderTemplate(Lang, this.DirectoryPath, this.DoubleSubject);
            Generator.Generate();
        }

        public void CreateHandleOutFile()
        {
            if (this.DirectoryPath == null && this.DoubleFilePath == null)
                throw new NotImplementedException("Only the outfile command switch (is currently supported.");
            if (this.DoubleFilePath != null)
            {
                this.OutFile = new FileInfo(this.DoubleFilePath);
            }
            else
            {
                this.OutFile = new FileInfo(Path.Combine(this.DirectoryPath, string.Format("Double{0}.{1}", this.DoubleSubject.Name, this.Language)));
            }
        }

        public void FindTypeToDouble()
        {
            using (TextReader ClassReader = new StreamReader(this.SourceFilePath))
            {
                string Namespace = string.Empty;
                string Line = string.Empty;
                for (int i = 1; i < this.LineNumber; i++)
                {
                    Line = ClassReader.ReadLine();
                    if (Regex.IsMatch(Line, @"^\s{0,}Namespace\s+"))
                    {
                        string Rx = @"^\s{0,}Namespace\s+(\w+)$";
                        if (Namespace == string.Empty)
                        {
                            Namespace = Regex.Match(Line, Rx).Groups[1].Value;
                        }
                        else
                        {
                            Namespace = string.Concat(string.Format(".{0}", Regex.Match(Line, Rx).Groups[1].Value));
                        }
                    }
                    
                }
                string ClassDeclaration = ClassReader.ReadLine();
                string ClassName = Regex.Match(ClassDeclaration, @"[Interface|Class]\s+(\w+)$").Groups[1].Value;
                if (Namespace != string.Empty)
                    ClassName = string.Format("{0}.{1}", Namespace, ClassName);
                Assembly SubjectAsm = Assembly.LoadFrom(this.AsmPath);
                try
                {
                    this.DoubleSubject = SubjectAsm.GetType(ClassName);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex.ToString());
                }
                if (this._DoubleSubject == null)
                {
                    string Rx = string.Format("{0}$", ClassName);
                    foreach (Type Possible in SubjectAsm.GetTypes())
                    {
                        if (Regex.IsMatch(Possible.FullName, Rx))
                        {
                            this.DoubleSubject = Possible;
                            break;
                        }
                    }
                }
            }
        }
    }
}
